/**
 * 
 */
package cn.javacc.core.database;

import java.util.List;
import java.util.Map;

import javax.persistence.EntityManager;
import javax.persistence.NonUniqueResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cn.javacc.core.util.Hql;
import cn.javacc.core.vo.PageData;
import cn.javacc.util.Globals;

/**
 * @author mzh2008@163.com 2012-11-11 上午8:42:46
 * 
 */
public class BaseDao<T> {
	private final Logger logger = LoggerFactory.getLogger(BaseDao.class);
	@PersistenceContext
	protected EntityManager entityManager;

	private Class<T> entityClass;

	public BaseDao(Class<T> entityClass) {
		this.entityClass = entityClass;
	}

	public T get(Object id) {
		try {
			return entityManager.find(entityClass, id);
		} finally {
			logger.error("get, entityClass={}, id={}", new Object[] { entityClass.getName(), id });
		}
	}

	public void save(T entity) {
		try {
			entityManager.persist(entity);
		} finally {
			logger.error("get, entityClass={}", entity.getClass().getName());
		}
	}

	public void update(T entity) {
		try {
			entityManager.merge(entity);
		} finally {
			logger.error("update, entityClass={}", entity.getClass().getName());
		}
	}

	public void delete(T entity) {
		try {
			entityManager.remove(entity);
		} finally {
			logger.error("delete, entityClass={}", entity.getClass().getName());
		}
	}

	private void addParams(Object[] params, Query query) {
		if (params != null && params.length > 0) {
			for (int i = 0; i < params.length; i++) {
				query.setParameter(i, params[i]);
			}
		}
	}

	@SuppressWarnings("unchecked")
	public PageData<T> queryForPage(Hql hql, Integer toPage, Integer pageSize) {
		String temphql = "select count(*) " + hql.getHqlStr();
		Query query = entityManager.createQuery(temphql);
		addParams(hql.getParams().toArray(), query);//
		Long totalRows = (Long) query.getSingleResult();
		PageData<T> pageData = new PageData<T>();
		pageData.setTotalRows(Integer.valueOf(totalRows.toString()));
		if (toPage == null || toPage < 1) {
			toPage = 1;
		}
		if (pageSize == null || pageSize < 1) {
			pageSize = Globals.PAGE_SIZE;
		}
		pageData.setPageSize(pageSize);
		pageData.setCurrentPage(toPage);

		Integer startRow = pageData.getStartRow();

		query = entityManager.createQuery(hql.getHqlStr());
		addParams(hql.getParams().toArray(), query);//
		query.setFirstResult(startRow);
		query.setMaxResults(pageSize);

		pageData.setData(query.getResultList());
		return pageData;
	}

	@SuppressWarnings("unchecked")
	public List<T> find(String queryString, Map<String, Object> params) {
		try {
			Query query = entityManager.createQuery(queryString);
			if (params != null)
				for (Map.Entry<String, Object> entry : params.entrySet()) {
					query.setParameter(entry.getKey(), entry.getValue());
				}
			return query.getResultList();
		} finally {
			logger.error("find, query={}, params={}", new Object[] { queryString, params });
		}
	}

	@SuppressWarnings("unchecked")
	public T findUniqueResult(String queryString, Map<String, Object> params) {
		try {
			Query query = entityManager.createQuery(queryString);
			if (params != null)
				for (Map.Entry<String, Object> entry : params.entrySet()) {
					query.setParameter(entry.getKey(), entry.getValue());
				}
			List<T> results = query.getResultList();
			return getUniqueResult(results);
		} finally {
			logger.debug("findUniqueResult, query={}, params={}", new Object[] { queryString, params });
		}
	}

	private T getUniqueResult(List<T> results) {
		if (results.isEmpty())
			return null;
		if (results.size() > 1) {
			throw new NonUniqueResultException("result returned more than one element, returnedSize=" + results.size());
		}
		return results.get(0);
	}
}
